package com.huohuzhihui.client;

import com.huohuzhihui.config.ContractConfig;
import com.huohuzhihui.contract.Asset;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.List;
import java.util.Properties;

@Service
@NoArgsConstructor
@Data
public class AssetClient {

  static Logger logger = LoggerFactory.getLogger(AssetClient.class);

  @Autowired
  private Client client;

  private String address = "0xe08a8731293f43f6db116b9ac1a0e70bb677cce8";

  @Autowired
  private ContractConfig contractConfig;

  AssembleTransactionProcessor txProcessor;


  @PostConstruct
  public void init() throws Exception {
    this.txProcessor =
            TransactionProcessorFactory.createAssembleTransactionProcessor(
                    this.client, this.client.getCryptoSuite().getCryptoKeyPair());
//    this.address = contractConfig.getTestAddress();
  }


  public void deployAssetAndRecordAddr() {

    try {
      Asset asset = Asset.deploy(client, this.client.getCryptoSuite().getCryptoKeyPair());
      System.out.println(
          " deploy Asset success, contract address is " + asset.getContractAddress());

      recordAssetAddr(asset.getContractAddress());
    } catch (Exception e) {
      // TODO Auto-generated catch block
      // e.printStackTrace();
      System.out.println(" deploy Asset contract failed, error message is  " + e.getMessage());
    }
  }

  public void recordAssetAddr(String address) throws FileNotFoundException, IOException {
    Properties prop = new Properties();
    prop.setProperty("address", address);
    final Resource contractResource = new ClassPathResource("contract.properties");
    FileOutputStream fileOutputStream = new FileOutputStream(contractResource.getFile());
    prop.store(fileOutputStream, "contract address");
  }

  public String loadAssetAddr() throws Exception {
    // load Asset contact address from contract.properties
    Properties prop = new Properties();
    final Resource contractResource = new ClassPathResource("contract.properties");
    prop.load(contractResource.getInputStream());

    String contractAddress = prop.getProperty("address");
    if (contractAddress == null || contractAddress.trim().equals("")) {
      throw new Exception(" load Asset contract address failed, please deploy it first. ");
    }
    logger.info(" load Asset address from contract.properties, address is {}", contractAddress);
    return contractAddress;
  }

  public Tuple2<BigInteger, BigInteger> queryAssetAmount(String assetAccount) {
    try {
      Asset asset = Asset.load(this.address, client, this.client.getCryptoSuite().getCryptoKeyPair());
      Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount);
      if (result.getValue1().compareTo(new BigInteger("0")) == 0) {
        System.out.printf(" asset account %s, value %s \n", assetAccount, result.getValue2());
        return result;
      } else {
        System.out.printf(" %s asset account is not exist \n", assetAccount);
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      // e.printStackTrace();
      logger.error(" queryAssetAmount exception, error message is {}", e.getMessage());

      System.out.printf(" query asset account failed, error message is %s\n", e.getMessage());
    }
    return null;
  }

  public List<Asset.RegisterEventEventResponse> registerAssetAccount(String assetAccount, BigInteger amount) {
    try {

      Asset asset = Asset.load(this.address, client, this.client.getCryptoSuite().getCryptoKeyPair());
      TransactionReceipt receipt = asset.register(assetAccount, amount);
      List<Asset.RegisterEventEventResponse> response = asset.getRegisterEventEvents(receipt);
      if (!response.isEmpty()) {
        if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
          System.out.printf(
              " register asset account success => asset: %s, value: %s \n", assetAccount, amount);
        } else {
          System.out.printf(
              " register asset account failed, ret code is %s \n", response.get(0).ret.toString());
        }
      } else {
        System.out.println(" event log not found, maybe transaction not exec. ");
      }
      return response;
    } catch (Exception e) {
      // TODO Auto-generated catch block
      // e.printStackTrace();
e.printStackTrace();
      logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
      System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
    }
    return null;
  }

  public void transferAsset(String fromAssetAccount, String toAssetAccount, BigInteger amount) {
    try {
      String contractAddress = loadAssetAddr();
      Asset asset = Asset.load(contractAddress, client, this.client.getCryptoSuite().getCryptoKeyPair());
      TransactionReceipt receipt = asset.transfer(fromAssetAccount, toAssetAccount, amount);
      List<Asset.TransferEventEventResponse> response = asset.getTransferEventEvents(receipt);
      if (!response.isEmpty()) {
        if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
          System.out.printf(
              " transfer success => from_asset: %s, to_asset: %s, amount: %s \n",
              fromAssetAccount, toAssetAccount, amount);
        } else {
          System.out.printf(
              " transfer asset account failed, ret code is %s \n", response.get(0).ret.toString());
        }
      } else {
        System.out.println(" event log not found, maybe transaction not exec. ");
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      // e.printStackTrace();

      logger.error(" registerAssetAccount exception, error message is {}", e.getMessage());
      System.out.printf(" register asset account failed, error message is %s\n", e.getMessage());
    }
  }


}
